#include "system_uart.h"

uint8_t receive_buff[1024] = {0};

void system_uart_init(void)
{
    USART_InitTypeDef USART_InitStruct;
    GPIO_InitTypeDef GPIO_InitStruct;

    RCC_AHB1PeriphClockCmd(SYSTEM_UART_TX_CLOCK | SYSTEM_UART_RX_CLOCK, ENABLE);
    RCC_APB1PeriphClockCmd(SYSTEM_UART_CLOCK, ENABLE);

    GPIO_InitStruct.GPIO_Pin = SYSTEM_UART_TX_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(SYSTEM_UART_TX_PORT, &GPIO_InitStruct);
    GPIO_PinAFConfig(SYSTEM_UART_TX_PORT, SYSTEM_UART_TX_SOURCE, GPIO_AF_USART2);

    GPIO_InitStruct.GPIO_Pin = SYSTEM_UART_RX_PIN;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_Speed = GPIO_High_Speed;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(SYSTEM_UART_RX_PORT, &GPIO_InitStruct);
    GPIO_PinAFConfig(SYSTEM_UART_RX_PORT, SYSTEM_UART_RX_SOURCE, GPIO_AF_USART2);

    USART_InitStruct.USART_BaudRate = SYSTEM_UART_BAUD;
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    USART_InitStruct.USART_Parity = USART_Parity_No;
    USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

    USART_Init(SYSTEM_UART, &USART_InitStruct);
    USART_Cmd(SYSTEM_UART, ENABLE);
    USART_ITConfig(SYSTEM_UART, USART_IT_RXNE, ENABLE);
}

void send_char(USART_TypeDef * pUSARTx,uint8_t ch)
{
    USART_SendData(pUSARTx, ch);
    while((USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET));
}

int fputc(int ch, FILE *f)
{
		USART_SendData(SYSTEM_UART, (uint8_t) ch);
		while (USART_GetFlagStatus(SYSTEM_UART, USART_FLAG_TXE) == RESET);		
		return (ch);
}

int fgetc(FILE *f)
{
		while (USART_GetFlagStatus(SYSTEM_UART, USART_FLAG_RXNE) == RESET);
		return (int)USART_ReceiveData(SYSTEM_UART);
}

void system_putc(uint8_t ch)
{
    send_char(SYSTEM_UART,ch);
}

void system_puts(char* str)
{
    do{
        send_char(SYSTEM_UART,*str);
    }while(*(str++) != '\0');
}

void receive_data(USART_TypeDef * pUSARTx)
{   
    uint16_t size = sizeof(receive_buff);
    static uint16_t len = 0;
    static int index = 0;
    static PACKAGE step = HEAD;

    if((USART_GetITStatus(pUSARTx,USART_IT_RXNE)!=RESET))
    {
        uint8_t tmprec = (uint8_t)USART_ReceiveData(pUSARTx);

        switch(step)
        {
            case HEAD:
                if(tmprec == (uint8_t)PAK_HEAD)
				{
                    memreset(receive_buff, 0, sizeof(receive_buff), '\0');
                    index = 0;
                    len = 0;
					receive_buff[index++] = tmprec;
                    step = LENGTHH;
				}
                else if(index == 0 && len == 0)
                {
                    printf("error: this device haed is 0X%X\n", PAK_HEAD);
                }
                else
                {
                    memreset(receive_buff, 0, sizeof(receive_buff), '\0');
                    printf("error: you must check the package actual length and head or other ...\n");
                    printf("message: the rec_buff will be reset.\n");
                }

                break;
            case LENGTHH:
                receive_buff[index++] = tmprec;
                len = len | (0XFF00)&(receive_buff[LENGTHH] << 8);
                step = LENGTHL;
                break;
            case LENGTHL:
                receive_buff[index++] = tmprec;
                len = len | (0X00FF)&(receive_buff[LENGTHL]);

                if(len < 4)
                {
                    printf("error: the predefined length must greater than 4. the rec_buff will be reset.\n");
                    memreset(receive_buff, 0, sizeof(receive_buff), '\0');
                    step = HEAD;
                    break;
                }
                if(len > sizeof(receive_buff))
                {
                    printf("error: the predefined length must less than 1k. the rec_buff will be reset.\n");
                    step = HEAD;
                    break;
                }
                step = COMMAND;
                break;
            case COMMAND:
                    receive_buff[index++] = tmprec;

                    if(index == len)
                    {
                        step = HEAD;
                    }
                break;
            default:
                step = HEAD;
                break;
        }
    }
}

void memreset(uint8_t mem[], uint16_t bindex, uint16_t eindex, uint8_t vlaue)
{
	for(; bindex < eindex; bindex++)
	{
		mem[bindex] = vlaue;
	}
}